package com.vf.websocket.service;

import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;

import javax.websocket.*;
import javax.websocket.server.PathParam;
import javax.websocket.server.ServerEndpoint;

import com.jfinal.kit.JsonKit;
import com.jfinal.kit.StrKit;
import com.jfinal.log.Log;
import com.vf.core.render.RenderBean;
import com.vf.core.util.UuidUtil;
import com.vf.s.common.model.biz.BizWsLog;
import com.vf.websocket.common.constant.Status;
import com.vf.websocket.common.model.Client;
import com.vf.websocket.common.model.Message;
import com.vf.websocket.common.util.ClientUtil;

import net.sf.json.JSONObject;

@ServerEndpoint("/websocket/{auth}/{source}")
public class WebSocketServer {

	protected final Log log = Log.getLog(getClass());
	public static ConcurrentHashMap<String, Session> sessionMap = new ConcurrentHashMap<String, Session>();

	@OnOpen
	public void onOpen(Session session, @PathParam("auth") String auth, @PathParam("source") int source) {
		if(!sessionMap.containsKey(auth)) {
			sessionMap.put(auth, session);
			ClientUtil.put(source,auth, new Client(auth,source));
			log.info(String.format("WebSocket >> source【%s】有一连接加入！, 当前在线人数为  %s", source,ClientUtil.getSize(source)));
			onlineClient(auth, source);
		}else {
			sessionMap.put(auth, session);
		}
	}

	@OnMessage
	public void onMessage(String json, Session session, @PathParam("auth") String auth, @PathParam("source") int source) {
		try {
			if (StrKit.isBlank(json)) {
				session.getAsyncRemote().sendText(json);
				return;
			}
			Message message = (Message) JSONObject.toBean(JSONObject.fromObject(json), Message.class);
			if (message == null) {
				sendError(auth,"MSG_STATUS",UuidUtil.getUUID(),"消息格式有误!");
				return;
			}
			if(StrKit.equals("GET_USERS_ONLINE", message.getCode())) {
				getUsers(auth,message.getScope(),message.getUuid());
				return;
			}
			handle(auth, message,json);
		} catch (Exception e) {
			sendError(auth,"MSG_STATUS",UuidUtil.getUUID(),e.getMessage());
		}
	}

	@OnError
	public void onError(Session session, Throwable e, @PathParam("auth") String auth, @PathParam("source") int source) {
		sendError(auth,"MSG_STATUS",UuidUtil.getUUID(),e.getMessage());
	}

	@OnClose
	public void onClose(Session session, CloseReason closeReason, @PathParam("auth") String auth,@PathParam("source") int source) {
		closeClient(auth, source);
		ClientUtil.remove(source, auth);
		sessionMap.remove(auth);
		log.info(String.format("WebSocket >> source【%s】有一连接关闭！, 当前在线人数为  %s", source, ClientUtil.getSize(source)));
	}

	public void handle(String auth, Message message,String json) {
		String senderId = message.getSenderId();
		String receiverId = message.getReceiverId();
		String code = message.getCode();
		int scope = message.getScope();
		if(!StrKit.isBlank(receiverId) && sessionMap.containsKey(receiverId)) {
			send(receiverId,json);
			saveLog(senderId, receiverId, code, scope, json);
		}else {
			int size=ClientUtil.getSize(scope);
			if(size==0) {
				log.info(String.format("WebSocket >> 【%s】类型客户端不在线！", scope));
				sendError(auth,code,message.getUuid(),String.format("【%s】类型客户端不在线！", scope));
				return;
			}
			Map<String, Client> clientMap=ClientUtil.gets(scope);
			if(clientMap!=null && clientMap.size()>0) {
				for(Map.Entry<String, Client> entry : clientMap.entrySet()){
				   String key = entry.getKey();
				   if(sessionMap.containsKey(key)) {
					   send(key,json);
				   }
				}
			}else {
				sendError(auth,code,message.getUuid(),String.format("【%s】类型客户端不在线！", scope));
				log.info(String.format("WebSocket >> 【%s】类型客户端不在线！", scope));
			}
		}
	}
	
	/**
	 * 发送消息
	 * @param session
	 * @param message
	 */
	private synchronized  void send(String auth,String message) {
		if(!StrKit.isBlank(auth)) {
            try {
            	if(sessionMap.containsKey(auth)) {
            		Session session=sessionMap.get(auth);
            		synchronized(session) {
            			session.getBasicRemote().sendText(message);
            		}
            	}
            } catch (Exception e){
                System.out.println("ws send exception : " +e.toString());
            }
		}
	}
	
	/**
	 * 获取在线用户
	 * @param session
	 * @param scope
	 */
	private void getUsers(String auth,int scope,String timestamp) {
		Map<String, Client> clientMap=ClientUtil.gets(scope);
		if(clientMap!=null && clientMap.size()>0) {
			List<Client> list=new LinkedList<Client>();
			for(Map.Entry<String, Client> entry : clientMap.entrySet()){
			   String key = entry.getKey();
			   if(sessionMap.containsKey(key)) {
				   list.add(entry.getValue());
			   }
			}
			sendSuccess( auth, "GET_USERS_ONLINE",timestamp,list);
		}else {
			sendError(auth,"GET_USERS_ONLINE",timestamp,String.format("【%s】类型客户端不在线！", scope));
			log.info(String.format("WebSocket >> 【%s】类型客户端不在线！", scope));
		}
	}
	
	/**
	 * 成功提示
	 * @param session
	 * @param code
	 * @param data
	 */
	private void sendSuccess(String auth,String code,String timestamp,Object data) {
		Message message = new Message();
		message.setCode(code);
		
		RenderBean renderBean = new RenderBean();
		renderBean.setCode(Status.SUCCESS);
		renderBean.setMessage(Status.SUCCESS_MSG);
		renderBean.setData(data);
		send(auth,JsonKit.toJson(renderBean));
	}
	
	/**
	 * 错误提示
	 * @param session
	 * @param code
	 * @param error
	 */
	private void sendError(String auth,String code,String timestamp,String error) {
		Message message = new Message();
		message.setCode(code);
		RenderBean renderBean = new RenderBean();
		renderBean.setCode(Status.ERROR);
		renderBean.setMessage(error);
		send(auth,JsonKit.toJson(renderBean));
	}
	
	/**
	 * 日记
	 * @param senderId
	 * @param receiverId
	 * @param code
	 * @param scope
	 * @param content
	 */
	private void saveLog(String senderId, String receiverId, String code, int scope, String content) {
		try {
			BizWsLog bizWsLog = new BizWsLog();
			bizWsLog.setId(UuidUtil.getUUID());
			bizWsLog.setCode(code);
			bizWsLog.setContent(content);
			bizWsLog.setReceiverId(receiverId);
			bizWsLog.setSenderId(senderId);
			bizWsLog.setScope(scope+"");
			bizWsLog.save();
		} catch (Exception e) {
		}
	}
	
	/**
	 * 客户端上线
	 * @param auth
	 * @param source
	 */
	public void onlineClient(String auth,int source) {
		Client client=ClientUtil.get(source, auth);
		if(client!=null) {
			Message message = new Message();
			message.setCode("ONLINE_CLIENT");
			message.setData(client);
			message.setUuid(UuidUtil.getUUID());
			Map<String, Client> clientMap=ClientUtil.gets(1);
			if(clientMap!=null && clientMap.size()>0) {
				for(Map.Entry<String, Client> entry : clientMap.entrySet()){
				   String key = entry.getKey();
				   if(sessionMap.containsKey(key)) {
					   this.send(key, JsonKit.toJson(message));
				   }
				}
			}
		}
	}
	
	/**
	 * 客户端掉线
	 * @param auth
	 */
	public void closeClient(String auth,int source) {
		Client client=ClientUtil.get(source, auth);
		if(client!=null) {
			Message message = new Message();
			message.setCode("CLOSE_CLIENT");
			message.setData(client);
			message.setUuid(UuidUtil.getUUID());
			Map<String, Client> clientMap=ClientUtil.gets(1);
			if(clientMap!=null && clientMap.size()>0) {
				for(Map.Entry<String, Client> entry : clientMap.entrySet()){
				   String key = entry.getKey();
				   if(sessionMap.containsKey(key)) {
					   this.send(key, JsonKit.toJson(message));
				   }
				}
			}
			
		}
	}
	
}
